#pragma once

#include "Utils.h"
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <glm/glm.hpp>
#include <string>
constexpr int numVBOs = 2;
const std::string shaderPath = "./shaders/";

const float vertexPositions[108] = {
    -1.0f, 1.0f,  -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,  -1.0f, -1.0f, 1.0f,  -1.0f,
    -1.0f, 1.0f,  1.0f,  -1.0f, -1.0f, 1.0f,  -1.0f, 1.0f,  -1.0f, -1.0f, 1.0f,
    -1.0f, 1.0f,  1.0f,  1.0f,  -1.0f, 1.0f,  -1.0f, 1.0f,  1.0f,  1.0f,  1.0f,
    1.0f,  1.0f,  -1.0f, 1.0f,  -1.0f, 1.0f,  -1.0f, -1.0f, 1.0f,  1.0f,  1.0f,
    1.0f,  -1.0f, -1.0f, 1.0f,  -1.0f, 1.0f,  1.0f,  1.0f,  1.0f,  1.0f,  -1.0f,
    -1.0f, 1.0f,  -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,  1.0f,  -1.0f, -1.0f, -1.0f,
    -1.0f, 1.0f,  -1.0f, -1.0f, 1.0f,  1.0f,  -1.0f, -1.0f, 1.0f,  1.0f,  -1.0f,
    1.0f,  1.0f,  -1.0f, -1.0f, 1.0f,  -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
    -1.0f, 1.0f,  -1.0f, 1.0f,  -1.0f, 1.0f,  1.0f,  -1.0f, 1.0f,  1.0f,  1.0f,
    1.0f,  1.0f,  1.0f,  -1.0f, 1.0f,  1.0f,  -1.0f, 1.0f,  -1.0f};

class Display {
public:
  Display(sf::Window &window) : win(window) { init(); }

  void init() {
    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);
    glGenBuffers(numVBOs, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions,
                 GL_STATIC_DRAW);
    using std::string;
    string vertexShaderPath = shaderPath + "v.vert";
    string fragmentShaderPath = shaderPath + "f.frag";

    renderingProgram = Utils::createShaderProgram(shaderPath + "v.vert",
                                                  shaderPath + "f.frag");

    cameraX = 0.0f;
    cameraY = 0.0f;
    cameraZ = 16.0f;
    cubeLocX = 0.0f;
    cubeLocY = -2.0f;
    cubeLocZ = 0.0f; // 沿 y 轴下移以展示透视
  }
  void render() {
    glClear(GL_DEPTH_BUFFER_BIT);
    glUseProgram(renderingProgram);
    // 获取 MV 矩阵和投影矩阵的统一变量
    mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
    projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");
    // 构建透视矩阵
    auto size = win.getSize();
    width = size.x;
    height = size.y;

    aspect = (float)width / (float)height;
    pMat = glm::perspective(1.0472f, aspect, 0.1f,
                            1000.0f); // 1.0472 radians = 60 degrees
    // 构建视图矩阵、模型矩阵和 MV 矩阵
    vMat = glm::translate(glm::mat4(1.0f),
                          glm::vec3(-cameraX, -cameraY, -cameraZ));
    mMat = glm::translate(glm::mat4(1.0f),
                          glm::vec3(cubeLocX, cubeLocY, cubeLocZ));
    mvMat = vMat * mMat;

    // 将透视矩阵和 MV 矩阵复制给相应的统一变量
    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));
    // 将 VBO 关联给顶点着色器中相应的顶点属性
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    // 调整 OpenGL 设置，绘制模型
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDrawArrays(GL_TRIANGLES, 0, 36);
  }

private:
  sf::Window &win;
  float cameraX, cameraY, cameraZ;
  float cubeLocX, cubeLocY, cubeLocZ;
  GLuint renderingProgram;
  GLuint vao[1];
  GLuint vbo[2];

  GLuint mvLoc, projLoc;
  int width, height;
  float aspect;
  glm::mat4 pMat, vMat, mMat, mvMat;
};